package interfacelearn

import "fmt"

//接口是一个协议
//程序员-只要你能够：1.写代码， 2.解决bug  其实就是一组方法的集合

type Programmer interface {
	Coding() string //方法只是一个声明
	Debug() string
}

type Designer interface {
	Design() string
}

type Manager interface {
	Programmer
	Designer
	Manage() string
}

type UIDesigner struct {
}

type Pythoner struct {
	UIDesigner
	lib   []string
	kj    []string
	years int
}

type Gopher struct {
}

func (d UIDesigner) Design() string {
	return "我会ui设计"
}

func (p Pythoner) Coding() string {
	return "python 开发者"
}

func (p Pythoner) Debug() string {
	return "我会python的debug"
}

//func (p Pythoner) Design() string {
//	return "我不仅能写python还会设计"
//}

func (p Pythoner) Manage() string {
	return "不好意思，写python那是以前，现在我搞管理了"
}

func (g Gopher) Coding() string {
	return "go 开发者"
}

func (g Gopher) Debug() string {
	return "我会golang的debug"
}

//对于Pythoner这个结构体来说，你实现任何方法都可以，但是你只要不全部实现Coding，Debug你就不是Programmer类型
//1.Pythoner本身自己就是一个类型，那我何必在意是不是Programmer呢？
//2.面向对象，封装、继承、多态 - 多态的概念对于pythoner来说，有点陌生。
//3.对interface做一个说明：在go语言中，接口是一种类型（抽象类型）

// 开发中经常会遇到的问题
// 开发一个电商网站，支付环节：微信、支付宝、银行卡。你的系统支持各种类型的支付。每一种支付都有同一的接口
//定义一个协议1.创建订单，2.支付，3.查询支付状态，4.退款

type AliPay struct {
}

type WechatPay struct {
}

type BankPay struct {
}

//多态
// 调用的时候，不知道要实例化哪一个？需要申明的是一种通用的类型，比如父类。但实际使用的是另一种类型（如：子类）

//再一个场景：缓存
//开始的时候使用的是redis,但是后期考虑使用memcache,或者本地缓存
//开始的时候，我们只要申明一个通用的缓存类型，定义一些方法（协议）。其他的缓存只要实现这些协议即可

func InterfaceLearn() {
	var pro Programmer

	//接口帮我们实现了多态
	pro = Pythoner{}
	fmt.Println(pro.Debug())

	pro = Gopher{}
	fmt.Println(pro.Debug())

	var pros []Programmer
	pros = append(pros, Pythoner{})
	pros = append(pros, Gopher{})

	//接口虽然是一种类型，但是和其他类型不太一样，接口是一种抽象类型。struct是具象
	p := Pythoner{}
	fmt.Printf("Pythoner类型： %T \n", p)
	//Programmer类型的变量，没有一个实实在在的类型，他是由我们赋值的类型确定的
	fmt.Printf("Programer类型： %T \n", pro)

	//go struct组合  组合一起实现了所有的接口方法也是可以的
	//接口本身，也支持组合
	var m Manager = Pythoner{}
	fmt.Println(m.Manage())
	fmt.Println(m.Design())
	//所以，1.接口支持组合，2.结构体组合实现了所有的接口方法也没有问题
}
